using System;
using System.Linq;
using FireStarter.Base;
using FireStarter.Base.BusinessObjectMerger;
using FireStarterModeller.BO;
using FireStarterModeller.Logic;
using FireStarterModeller.Logic.MergeBusinessObjects;
using FireStarterModeller.Test.BO;
using Habanero.BO;
using NUnit.Framework;
using Rhino.Mocks;

namespace FireStarterModeller.Test.Logic.MergeBusinessObjects
{
    [TestFixture]
    public class TestMergeDMProps
    {
        [TestFixtureSetUp]
        public virtual void TestFixtureSetup()
        {
            TestUtilsLogic.SetupFixture();
        }
        [SetUp]
        public virtual void SetupTest()
        {
            TestUtilsLogic.SetupTest();
        }
        [Test]
        public void Test_MergeDMProperty_WhenMergeToNotNull_ShouldUpdateDMProperty()
        {
            //---------------Set up test pack-------------------
            IMergeBO<DMProperty> mergeBO = MergeableBORegistry.Instance.Resolve<DMProperty>();
            var fromDMProp = TestUtilsDMProperty.CreateUnsavedValidDMProperty_WithClassNull();
            fromDMProp.DefaultValue = "SomeValue";
            var toDmProp = new DMProperty();
            //---------------Assert Precondition----------------
            Assert.AreNotEqual(fromDMProp.DefaultValue, toDmProp.DefaultValue);
            //---------------Execute Test ----------------------
            mergeBO.MergeBOFrom(fromDMProp, toDmProp);
            //---------------Test Result -----------------------
            Assert.AreEqual(fromDMProp.DefaultValue, toDmProp.DefaultValue);
        }

        [Test]
        public void Test_MergeDMProperty_WhenMergePropHasASolution_ShouldUpdateDMPropertyType()
        {
            //---------------Set up test pack-------------------
            IMergeBO<DMProperty> mergeBO = MergeableBORegistry.Instance.Resolve<DMProperty>();
            var fromDMProp = TestUtilsDMProperty.CreateUnsavedValidDMProperty_WithClassNull();
            fromDMProp.PropertyType.AssemblyName = "System";
            fromDMProp.PropertyType.PropertyTypeName = "Decimal";
            DMClass savedDMClass = TestUtilsDMClass.CreateSavedDMClass();
            var toProp = new DMProperty {Class = savedDMClass};
            //---------------Assert Precondition----------------
            Assert.IsNotNull(fromDMProp.PropertyType);
            Assert.IsNotNullOrEmpty(fromDMProp.PropertyTypeString);
            //---------------Execute Test ----------------------
            DMProperty mergedDMProp = mergeBO.MergeBOFrom(fromDMProp, toProp);
            //---------------Test Result -----------------------
            Assert.AreNotSame(fromDMProp.PropertyType, mergedDMProp.PropertyType);
            Assert.AreEqual(fromDMProp.PropertyTypeString, mergedDMProp.PropertyTypeString);
        }
        [Test]
        public void Test_MergeDMProperty_WhenMergePropHasASolutionAndNotStdType_ShouldUpdateCreateDMPropertyType()
        {
            //---------------Set up test pack-------------------
            IMergeBO<DMProperty> mergeBO = MergeableBORegistry.Instance.Resolve<DMProperty>();
            var fromDMProp = TestUtilsDMProperty.CreateUnsavedValidDMProperty_WithClassNull();
            fromDMProp.PropertyType.AssemblyName = "System";
            fromDMProp.PropertyType.PropertyTypeName = "NonStd";
            DMClass savedDMClass = TestUtilsDMClass.CreateSavedDMClass();
            var toProp = new DMProperty {Class = savedDMClass};
            //---------------Assert Precondition----------------
            Assert.IsNotNull(fromDMProp.PropertyType);
            Assert.IsNotNullOrEmpty(fromDMProp.PropertyTypeString);
            //---------------Execute Test ----------------------
            DMProperty mergedDMProp = mergeBO.MergeBOFrom(fromDMProp, toProp);
            //---------------Test Result -----------------------
            Assert.AreNotSame(fromDMProp.PropertyType, mergedDMProp.PropertyType);
            Assert.AreEqual("System.NonStd", mergedDMProp.PropertyTypeString);
        }
        [Test]
        public void Test_MergeDMClass_WhenMergeNewProp_ShouldCreateNewProp()
        {
            //---------------Set up test pack-------------------
            IMergeBO<DMClass> mergeBO = MergeableBORegistry.Instance.Resolve<DMClass>();
            var fromDMProp = TestUtilsDMProperty.CreateUnsavedValidDMProperty();
            fromDMProp.PropertyTypeString = DMPropertyType.PROP_TYPE_DECIMAL;
            DMClass toDmCLass = TestUtilsDMClass.CreateUnsavedValidDMClass();
            
            //---------------Assert Precondition----------------
            Assert.IsNotNull(fromDMProp.PropertyType);
            Assert.IsNotNullOrEmpty(fromDMProp.PropertyTypeString);
            DMClass fromDMClass = (DMClass) fromDMProp.Class;
            Assert.GreaterOrEqual(1, fromDMClass.Properties.Count);
            Assert.AreEqual(0, toDmCLass.Properties.Count);
            //---------------Execute Test ----------------------
            DMClass mergedDMClass = mergeBO.MergeBOFrom(fromDMClass, toDmCLass);
            //---------------Test Result -----------------------
            Assert.AreEqual(fromDMClass.Properties.Count, mergedDMClass.Properties.Count);
            var toDMProp = mergedDMClass.GetDMProperty(fromDMProp.PropertyName);
            Assert.AreNotSame(fromDMProp.PropertyType, toDMProp.PropertyType);
            Assert.AreEqual(fromDMProp.PropertyTypeString, toDMProp.PropertyTypeString);
        }

        [Test]
        public void Test_MergeDMProp_WhenAddDefaultRule_ShouldClonePropRuleAndAddToProp()
        {
            //---------------Set up test pack-------------------
            IMergeBO<DMProperty> mergeBO = MergeableBORegistry.Instance.Resolve<DMProperty>();
            var fromDMProp = TestUtilsDMProperty.CreateUnsavedValidDMProperty_WithClassNull();
            var defaultPropRule = new DMPropRule
                                      {
                                          PropRuleName = TestUtilsShared.GetRandomString()
                                      };
            fromDMProp.DefaultPropRule = defaultPropRule;
            fromDMProp.DefaultValue = "SomeValue";
            var toDmProp = new DMProperty();
            //---------------Assert Precondition----------------
            Assert.IsNull(toDmProp.DefaultPropRule);
            //---------------Execute Test ----------------------
            mergeBO.MergeBOFrom(fromDMProp, toDmProp);
            //---------------Test Result -----------------------
            Assert.IsNotNull(toDmProp.DefaultPropRule);
            Assert.AreEqual(defaultPropRule.PropRuleName, toDmProp.DefaultPropRule.PropRuleName);
            Assert.AreNotSame(defaultPropRule, toDmProp.DefaultPropRule);
        }
        [Test]
        public void Test_MergeDMProp_WhenUpdateDefaultRule_ShouldClonePropRuleAndAddToProp()
        {
            //---------------Set up test pack-------------------
            IMergeBO<DMProperty> mergeBO = MergeableBORegistry.Instance.Resolve<DMProperty>();
            var fromDMProp = TestUtilsDMProperty.CreateUnsavedValidDMProperty_WithClassNull();
            var defaultPropRule = new DMPropRule
                                      {
                                          PropRuleName = TestUtilsShared.GetRandomString()
                                      };
            fromDMProp.DefaultPropRule = defaultPropRule;
            fromDMProp.DefaultValue = "SomeValue";
            var expectedToPropRule = new DMPropRule();
            var toDmProp = new DMProperty { DefaultPropRule = expectedToPropRule };

            //---------------Assert Precondition----------------
            Assert.IsNotNull(toDmProp.DefaultPropRule);
            Assert.AreNotEqual(defaultPropRule.PropRuleName, toDmProp.DefaultPropRule.PropRuleName);
            //---------------Execute Test ----------------------
            mergeBO.MergeBOFrom(fromDMProp, toDmProp);
            //---------------Test Result -----------------------
            Assert.IsNotNull(toDmProp.DefaultPropRule);
            Assert.AreEqual(defaultPropRule.PropRuleName, toDmProp.DefaultPropRule.PropRuleName);
            Assert.AreSame(expectedToPropRule, toDmProp.DefaultPropRule);
            Assert.AreNotSame(defaultPropRule, toDmProp.DefaultPropRule);
        }
        [Test]
        public void Test_MergeDMProp_WhenAddedRulesWithParameters_ShouldClonePropRuleAndParams()
        {
            //---------------Set up test pack-------------------
            IMergeBO<DMProperty> mergeBO = MergeableBORegistry.Instance.Resolve<DMProperty>();
            var fromDMProp = TestUtilsDMProperty.CreateUnsavedValidDMProperty_WithClassNull();
            var defaultPropRule = new DMPropRule
                                      {
                                          PropRuleName = TestUtilsShared.GetRandomString()
                                      };

            var fromPropRuleParam = CreatePropRuleParam(defaultPropRule);
            fromDMProp.DefaultPropRule = defaultPropRule;
            fromDMProp.DefaultValue = "SomeValue";
            var toDmProp = new DMProperty();
            //---------------Assert Precondition----------------
            Assert.IsNull(toDmProp.DefaultPropRule);
            //---------------Execute Test ----------------------
            mergeBO.MergeBOFrom(fromDMProp, toDmProp);
            //---------------Test Result -----------------------
            var toPropRule = toDmProp.DefaultPropRule;
            Assert.IsNotNull(toPropRule);
            Assert.AreEqual(1, toPropRule.PropRuleParameters.Count);
            var toPropRuleParam = toPropRule.PropRuleParameters.First();
            Assert.AreEqual(fromPropRuleParam.KeyName, toPropRuleParam.KeyName);
            Assert.AreEqual(ChangeType.Add, toPropRuleParam.PendingChangeType);
        }

        [Test]
        public void Test_MergeDMProp_WhenTwoAddedRulesWithParameters_ShouldClonePropRuleAndParams()
        {
            //---------------Set up test pack-------------------
            IMergeBO<DMProperty> mergeBO = MergeableBORegistry.Instance.Resolve<DMProperty>();
            var fromDMProp = TestUtilsDMProperty.CreateUnsavedValidDMProperty_WithClassNull();
            var defaultPropRule = new DMPropRule
                                      {
                                          PropRuleName = TestUtilsShared.GetRandomString()
                                      };

            var fromPropRuleParam = CreatePropRuleParam(defaultPropRule);
            var fromPropRuleParam2 = CreatePropRuleParam(defaultPropRule);
            fromDMProp.DefaultPropRule = defaultPropRule;
            var toDmProp = new DMProperty();
            //---------------Assert Precondition----------------
            Assert.IsNull(toDmProp.DefaultPropRule);
            //---------------Execute Test ----------------------
            mergeBO.MergeBOFrom(fromDMProp, toDmProp);
            //---------------Test Result -----------------------
            var toPropRule = toDmProp.DefaultPropRule;
            Assert.IsNotNull(toPropRule);
            Assert.AreEqual(2, toPropRule.PropRuleParameters.Count);
            var toPropRuleParam = toPropRule.PropRuleParameters.First();
            Assert.AreEqual(fromPropRuleParam.Value, toPropRuleParam.Value);
            var toPropRuleParam2 = toPropRule.PropRuleParameters.Last();
            Assert.AreEqual(fromPropRuleParam2.Value, toPropRuleParam2.Value);
        }

        [Test]
        public void Test_MergeDMPropRule_WhenTwoAddedRulesWithParameters_ShouldClonePropRuleParams()
        {
            //---------------Set up test pack-------------------
            IMergeBO<DMPropRule> mergeBO = new MergeBO<DMPropRule>();
            var fromPropRule = new DMPropRule
                                   {
                                       PropRuleName = TestUtilsShared.GetRandomString()
                                   };

            var fromPropRuleParam = CreatePropRuleParam(fromPropRule);
            var fromPropRuleParam2 = CreatePropRuleParam(fromPropRule);

            var toPropRule = new DMPropRule();

            //---------------Assert Precondition----------------
            Assert.AreEqual(0, toPropRule.PropRuleParameters.Count);
            //---------------Execute Test ----------------------
            mergeBO.MergeBOFrom(fromPropRule, toPropRule);
            //---------------Test Result -----------------------
            Assert.IsNotNull(toPropRule);
            Assert.AreEqual(2, toPropRule.PropRuleParameters.Count);
            var toPropRuleParam = toPropRule.PropRuleParameters.First();
            Assert.AreEqual(fromPropRuleParam.Value, toPropRuleParam.Value);
            var toPropRuleParam2 = toPropRule.PropRuleParameters.Last();
            Assert.AreEqual(fromPropRuleParam2.Value, toPropRuleParam2.Value);
        }

        [Test]
        public void Test_MergeDMPropRule_WhenTwoUpdatedRulesWithParameters_ShouldUpdateParams()
        {
            //---------------Set up test pack-------------------
            IMergeBO<DMPropRule> mergeBO = new MergeBO<DMPropRule>();
            var fromPropRule = new DMPropRule
                                   {
                                       PropRuleName = TestUtilsShared.GetRandomString()
                                   };

            var fromPropRuleParam = CreatePropRuleParam(fromPropRule);
            var fromPropRuleParam2 = CreatePropRuleParam(fromPropRule);


            var toPropRule = new DMPropRule();
            DMPropRuleParameter expectedToPropRuleParam = AddCopiedPropRuleParam(toPropRule, fromPropRuleParam);
            DMPropRuleParameter expectedToPropRuleParam2 = AddCopiedPropRuleParam(toPropRule, fromPropRuleParam2);

            //---------------Assert Precondition----------------
            Assert.AreEqual(2, toPropRule.PropRuleParameters.Count);
            Assert.AreNotEqual(fromPropRuleParam.Value, expectedToPropRuleParam.Value);
            Assert.AreNotEqual(fromPropRuleParam2.Value, expectedToPropRuleParam2.Value);
            //---------------Execute Test ----------------------
            mergeBO.MergeBOFrom(fromPropRule, toPropRule);
            //---------------Test Result -----------------------
            Assert.IsNotNull(toPropRule);
            Assert.AreEqual(2, toPropRule.PropRuleParameters.Count);
            var toPropRuleParam = toPropRule.PropRuleParameters.First();
            Assert.AreSame(expectedToPropRuleParam, toPropRuleParam);
            Assert.AreEqual(fromPropRuleParam.Value, toPropRuleParam.Value);
            var toPropRuleParam2 = toPropRule.PropRuleParameters.Last();
            Assert.AreSame(expectedToPropRuleParam2, toPropRuleParam2);
            Assert.AreEqual(fromPropRuleParam2.Value, toPropRuleParam2.Value);
        }

        [Test]
        public void Test_MergeDMPropRule_WhenOneRemovedParameters_ShouldUpdateParamsStatusToDelete()
        {
            //---------------Set up test pack-------------------
            IMergeBO<DMPropRule> mergeBO = new MergeBO<DMPropRule>();
            var fromPropRule = new DMPropRule
                                   {
                                       PropRuleName = TestUtilsShared.GetRandomString()
                                   };

            var fromPropRuleParam = CreatePropRuleParam(fromPropRule);
            var fromPropRuleParam2 = CreatePropRuleParam(fromPropRule);


            var toPropRule = new DMPropRule();
            DMPropRuleParameter expectedToPropRuleParam = AddCopiedPropRuleParam(toPropRule, fromPropRuleParam);
            DMPropRuleParameter expectedToPropRuleParam2 = AddCopiedPropRuleParam(toPropRule, fromPropRuleParam2);
            fromPropRule.PropRuleParameters.Remove(fromPropRuleParam2);
            //---------------Assert Precondition----------------
            Assert.AreEqual(1, fromPropRule.PropRuleParameters.Count);
            Assert.AreEqual(2, toPropRule.PropRuleParameters.Count);
            Assert.AreNotEqual(fromPropRuleParam.Value, expectedToPropRuleParam.Value);
            Assert.AreNotEqual(ChangeType.Update, expectedToPropRuleParam.PendingChangeType);
            Assert.AreNotEqual(ChangeType.Delete, expectedToPropRuleParam2.PendingChangeType);
            //---------------Execute Test ----------------------
            mergeBO.MergeBOFrom(fromPropRule, toPropRule);
            //---------------Test Result -----------------------
            Assert.IsNotNull(toPropRule);
            Assert.AreEqual(2, toPropRule.PropRuleParameters.Count);
            var toPropRuleParam = toPropRule.PropRuleParameters.First();
            var toPropRuleParam2 = toPropRule.PropRuleParameters.Last();
            /*            Assert.AreEqual(ChangeType.Update, toPropRuleParam.PendingChangeType);
                        Assert.AreEqual(ChangeType.Delete, toPropRuleParam2.PendingChangeType);*/
        }

        [Test]
        public void Test_MergeDMRelProp_ShouldMergeOwnerPropNameAndRelPropName()
        {
            //---------------Set up test pack-------------------
            IMergeBO<DMRelationshipProperty> relPropMerger = MergeableBORegistry.Instance.Resolve<DMRelationshipProperty>();
            var fromRelProp = new DMRelationshipProperty
                                  {
                                      OwnerPropertyName = TestUtilsShared.GetRandomString(),
                                      RelatedPropertyName = TestUtilsShared.GetRandomString()
                                  };
            //---------------Assert Precondition----------------
            Assert.IsNotNull(fromRelProp.ReverseRelationshipProperty);
            //---------------Execute Test ----------------------
            var mergedRelProp = relPropMerger.MergeBOFrom(fromRelProp, null);
            //---------------Test Result -----------------------
            Assert.IsNull(mergedRelProp.ReverseRelationshipProperty);
            Assert.AreEqual(fromRelProp.OwnerPropertyName, mergedRelProp.OwnerPropertyName);
            Assert.AreEqual(fromRelProp.RelatedPropertyName, mergedRelProp.RelatedPropertyName);
        }

        [Test]
        public void Test_MergeDMProp_WithRemovedSimpleLookup_ShouldRemoveSimpleLookup()
        {
            //---------------Set up test pack-------------------
            var propFrom = PropWithLList();
            IMergeBO<DMProperty> mergeProp = MergeableBORegistry.Instance.Resolve<DMProperty>();
            var propTo = mergeProp.MergeBOFrom(propFrom, null);
            DMLookupListSimple toLList = (DMLookupListSimple)propFrom.LookupList;
            toLList.ListItems.RemoveAll(item => true);
            //---------------Assert Precondition----------------
            Assert.AreEqual(0, ((DMLookupListSimple)propFrom.LookupList).ListItems.Count);
            Assert.AreEqual(1, ((DMLookupListSimple)propTo.LookupList).ListItems.Count);
            //---------------Execute Test ----------------------
            var mergedProp = mergeProp.MergeBOFrom(propFrom, null);
            //---------------Test Result -----------------------
            Assert.AreEqual(0, ((DMLookupListSimple)propFrom.LookupList).ListItems.Count);
            Assert.AreEqual(0, ((DMLookupListSimple)mergedProp.LookupList).ListItems.Count);
        }

        private static DMProperty PropWithLList()
        {
            DMProperty prop = new DMProperty();
            var simpleLl = new DMLookupListSimple();
            var dmListItem = new DMListItem {Display = "fdafa", Value = "fdafdas"};
            simpleLl.ListItems.Add(dmListItem);
            prop.LookupList = simpleLl;
            return prop;
        }

        private static DMPropRuleParameter AddCopiedPropRuleParam(DMPropRule toPropRule, DMPropRuleParameter fromPropRuleParam)
        {
            var expectedToPropRuleParam = new DMPropRuleParameter {KeyName = fromPropRuleParam.KeyName};
            toPropRule.PropRuleParameters.Add(expectedToPropRuleParam);
            return expectedToPropRuleParam;
        }

        private static DMPropRuleParameter CreatePropRuleParam(DMPropRule defaultPropRule)
        {
            var dmPropRuleParameter = defaultPropRule.PropRuleParameters.CreateBusinessObject();
            dmPropRuleParameter.KeyName = TestUtilsShared.GetRandomString();
            dmPropRuleParameter.Value = TestUtilsShared.GetRandomString();
            return dmPropRuleParameter;
        }
    }
}